package com.ctg.itrdc.imageconsole.service.impl;

import io.fabric8.kubernetes.api.model.Pod;

import java.util.Iterator;
import java.util.List;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.ctg.itrdc.imageconsole.common.constants.DockerConstant;
import com.ctg.itrdc.imageconsole.common.constants.K8sConstant;
import com.ctg.itrdc.imageconsole.common.util.TimeUtils;
import com.ctg.itrdc.imageconsole.data.dao.IK8sOperationRecordDao;
import com.ctg.itrdc.imageconsole.data.entity.K8sOperationRecord;
import com.ctg.itrdc.imageconsole.service.IK8sOperationRecordService;
import com.ctg.itrdc.imageconsole.util.KubeUtils;

@Component("k8sOperationRecordService")
public class K8sOperationRecordServiceImpl implements IK8sOperationRecordService {

	private static final Logger logger = LoggerFactory.getLogger(K8sOperationRecordServiceImpl.class);
	@Resource
	private IK8sOperationRecordDao k8sOperationRecordDao;

	@Override
	public Long saveRecord(String k8sUrl, String namespace, String rcName, Integer replicas, String operationObject,
			String operationType) {
		K8sOperationRecord k8sOperationRecord = new K8sOperationRecord();
		k8sOperationRecord.setK8sUrl(k8sUrl);
		k8sOperationRecord.setNamespace(namespace);
		k8sOperationRecord.setOperationId(rcName);
		k8sOperationRecord.setOperationObject(operationObject);
		k8sOperationRecord.setOperationType(operationType);
		k8sOperationRecord.setReplicas(replicas);
		k8sOperationRecord.setStatus(DockerConstant.K8sOperationRecord.EXECUTING);
		k8sOperationRecord.setCreateTime(TimeUtils.getNowDateStr());
		k8sOperationRecord.setLastUpdateTime(TimeUtils.getNowDateStr());
		k8sOperationRecord.setLockVersion(0l);
		return k8sOperationRecordDao.insert(k8sOperationRecord);
	}

	@Override
	public Integer updateRecordStatus(Long recordId, String status) {
		K8sOperationRecord k8sOperationRecord = new K8sOperationRecord();
		k8sOperationRecord.setId(recordId);
		k8sOperationRecord = k8sOperationRecordDao.selectByPrimaryKey(k8sOperationRecord);
		k8sOperationRecord.setStatus(status);
		k8sOperationRecord.setLastUpdateTime(TimeUtils.getNowDateStr());

		return k8sOperationRecordDao.updateByPrimaryKey(k8sOperationRecord);
	}

	@Override
	public List<K8sOperationRecord> getExecutingRecords() {
		K8sOperationRecord k8sOperationRecord = new K8sOperationRecord();
		k8sOperationRecord.setStatus(DockerConstant.K8sOperationRecord.EXECUTING);
		List<K8sOperationRecord> records = k8sOperationRecordDao.selectByExample(k8sOperationRecord);
		// 通过乐观锁机制 控制多进程拿同一数据进行操作的问题
		for (Iterator<K8sOperationRecord> it = records.iterator(); it.hasNext();) {
			K8sOperationRecord record = it.next();
			if (!k8sOperationRecordDao.tryOccupyLock(record)) {
				logger.warn("Failed to occupy lock for K8sOperationRecord ,id={}", record.getId());
				it.remove();
			}
		}
		return records;
	}

	@Override
	public void CheckExecutingRecords(K8sOperationRecord record) {
		if (DockerConstant.K8sOperationRecord.OPERATION_OBJECT_RC.equals(record.getOperationObject())) {
			if (DockerConstant.K8sOperationRecord.OPERATION_TYPE_RC_RESTART.equals(record.getOperationType())) {
				checkRestartRc(record);
			} else if (DockerConstant.K8sOperationRecord.OPERATION_TYPE_RC_SCALE.equals(record.getOperationType())) {
				checkScaleRc(record);
			} else if (DockerConstant.K8sOperationRecord.OPERATION_TYPE_RC_DELETE.equals(record.getOperationType())) {
				checkDeleteRc(record);
			}
		}
	}

	private void checkScaleRc(K8sOperationRecord record) {
		List<Pod> list = KubeUtils.queryPodsByRcName(record.getK8sUrl(), record.getOperationId());
		if (record.getReplicas() == 0 && list == null) {
			updateRecordStatus(record.getId(), DockerConstant.K8sOperationRecord.EXECUTE_SUCCESS);
		} else if (list == null) {
			return;
		} else {
			Integer runningPodNum = getRunningPodNum(list);
			if (record.getReplicas() == runningPodNum) {
				updateRecordStatus(record.getId(), DockerConstant.K8sOperationRecord.EXECUTE_SUCCESS);
			}
		}
	}

	private void checkRestartRc(K8sOperationRecord record) {
		List<Pod> list = KubeUtils.queryPodsByRcName(record.getK8sUrl(), record.getOperationId());
		if (list == null || list.size() == 0) {
			logger.info("在rc重启的检测中,通过rc={}没有找到pod", record.getOperationId());
			return;
		} else {
			Integer runningPodNum = getRunningPodNum(list);
			Integer notRunningNum = getNotRunningPodNum(list);
			if (record.getReplicas() == runningPodNum && notRunningNum == 0) {
				updateRecordStatus(record.getId(), DockerConstant.K8sOperationRecord.EXECUTE_SUCCESS);
			}
		}
	}

	private void checkDeleteRc(K8sOperationRecord record) {
		if (!KubeUtils.isRcExist(record.getK8sUrl(), record.getOperationId())) {
			updateRecordStatus(record.getId(), DockerConstant.K8sOperationRecord.EXECUTE_SUCCESS);
		}
	}

	private Integer getRunningPodNum(List<Pod> pods) {
		int runningNum = 0;
		for (Pod pod : pods) {
			String status = pod.getStatus().getPhase();
			if (K8sConstant.RUNNING_STATUS.equalsIgnoreCase(status)) {
				runningNum++;
			}
		}
		return runningNum;
	}

	private Integer getNotRunningPodNum(List<Pod> pods) {
		int notRunningNum = 0;
		for (Pod pod : pods) {
			String status = pod.getStatus().getPhase();
			if (!K8sConstant.RUNNING_STATUS.equalsIgnoreCase(status)) {
				notRunningNum++;
			}
		}
		return notRunningNum;
	}

	@Override
	public K8sOperationRecord queryByK8sOperationRecord(K8sOperationRecord record) {
		List<K8sOperationRecord> records = k8sOperationRecordDao.selectByExample(record);
		if (records != null && records.size() > 0) {
			return records.get(0);
		}
		return null;
	}
}
